//
//  BlePacket.swift
//  Pods
//
//  Created by tom on 2025/9/22.
//

import Foundation
import CoreBluetooth

class CharacteristicPacket{
    var data:Data? = nil
    var characteristic:CBCharacteristic? = nil
    var isVaild = false
    init() {
        
    }
}

enum BlePacketFormatError:Error{
    case firstDataError
    case sum
    case dataLength
}

class BlePacket{
    let cmd:CMD
    let dataLength:Int
    let sum:Int
    let data:Data?
    let raw:Data
    
    init(cmd:CMD, data:Data?) {
        self.cmd = cmd
        self.data = data
        self.dataLength = data?.count ?? 0
        var dataSum = 0
        if let d = data{
            for n in d{
                dataSum += Int(n & 0xff)
            }
        }
        self.sum = dataSum
        var raw = Data()
        raw += [CMD.magicCode.intValue, cmd.intValue]
        var binary = Binary()
        binary.writeInt(Int16(dataLength))
        if let d = try? binary.getAllBytes(){
            
            raw += d.reversed()
        }
        binary = Binary()
        binary.writeInt(Int32(sum), littleEndian: true)
        if let d = try? binary.getAllBytes(){
//            debugPrint("BlePacket checksum:\(d.toHexadecimal()),\(d.suffix(2).toHexadecimal())")
            raw += d.prefix(2)
        }
        
        if let d = data{
            
            raw += d
        }
        self.raw = raw
    }
    
    init(raw:Data) throws{
        if raw.first == CMD.magicCode.intValue{
            let cmdValue = raw[1]
            let cmd = CMD.fromByte(cmdValue)
            let data:Data? = raw.count == 6 ? nil : raw.subdata(in: 6..<raw.count)
            let dataLength = data?.count ?? 0
            let sum:Int = data?.reduce(0, {a, b in Int(a) + Int(b & 0xff)}) ?? 0
            var binary = Binary(bytes: [raw[3], raw[2]])
            
            if let dt = try? binary.readInt16(){
                if Int(dt) != dataLength{
                    debugPrint("dataLength")
                    throw BlePacketFormatError.dataLength
                }
            }
            
            binary = Binary(bytes: [raw[5], raw[4]])
            if let dt = try? binary.readInt16(){
                if Int(dt) != sum{
                    debugPrint("sum")
                    throw BlePacketFormatError.sum
                }
            }
            self.cmd = cmd
            self.dataLength = dataLength
            self.sum = sum
            self.data = data
            self.raw = raw
        }else{
            debugPrint("firstDataError")
            throw BlePacketFormatError.firstDataError
        }
    }
}

extension CMD{
    
    static func fromByte(_ byte:UInt8)->CMD{
        for i in 0..<40{
            if let cmd = CMD.init(rawValue: i){
                if cmd.intValue == byte{
                    return cmd
                }
            }
        }
        return CMD.unknow
    }
    
    var intValue:UInt8
    {
        get{
            switch self{
                
            case .magicCode:
                return 0xbc
            case .info:
                return 0x10
            case .imei:
                return 0x20
            case .imsi:
                return 0x21
            case .measTag:
                return 0x22
            case .measFlash:
                return 0x23
            case .measStatus:
                return 0x24
            case .measCount:
                return 0x25
            case .measSN:
                return 0x26
            case .measFlashCount:
                return 0x27
            case .measIndex:
                return 0x28
            case .rGSTSet:
                return 0x28
            case .rGSTGet:
                return 0x29
            case .ecgCtl:
                return 0x30
            case .ecgData:
                return 0x31
            case .ecgStatus:
                return 0x32
            case .dfuInit:
                return 0x40
            case .dfuPacket:
                return 0x41
            case .dfuCheck:
                return 0x42
            case .dfuEnd:
                return 0x43
            case .unknow:
                return 0x00
            case .writeFactSn:
                return 0x55
            case .ios:
                return 0x2a
            case .android:
                return 0x2b
            case .stopSync:
                return 0x2c
            case .timeCache:
                return 0x2d
            }
        }
    }
    
    
    
}


